﻿//========================================================= 
/**@file LC_ComStreamCmdAdapter.h
 * @brief 
 * 
 * @date 2016-01-04   17:02:26
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_LC_COMSTREAMCMDADAPTER_H_
#define _LIBZHOUYB_LC_COMSTREAMCMDADAPTER_H_
//--------------------------------------------------------- 
#include "../../../include/Base.h"
#include "../../../include/Extension.h"
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace lc {
//--------------------------------------------------------- 
/// LC流指令数据接收器
class LC_ComStreamCmdAdapter :
    public IInteractiveTrans,
    public DevAdapterBehavior<IInteractiveTrans>,
    public RefObject
{
protected:
    /// ACK应答指令
    static const byte _ACK_COMMAND[4];
public:
    /// ACK应答数据
    static const ByteArray ACK_COMMAND;
    /// 包头
    static const byte ACK_STX;
    /// 按照格式接收数据
    static bool RecvByFormat(IInteractiveTrans& dev, ByteBuilder& emptyBuff, ByteBuilder* pCacheBuff = NULL)
    {
        // 接收的长度不正确 
        if(IInteractiveTransHelper::ReadAssert(dev, 3, emptyBuff) != DevHelper::EnumSUCCESS)
            return false;

        // 数据头不正确
        if(emptyBuff[0] != ACK_STX)
            return false;

        // 检查长度位  XX 域的长度
        size_t len = emptyBuff[1];
        // 80 + LEN + XX + LRC 3字节
        size_t fulllen = (len + 3);
        // 数据没有接收全 
        if(IInteractiveTransHelper::ReadAssert(dev, fulllen, emptyBuff) != DevHelper::EnumSUCCESS)
            return false;
        // 缓存多接收的数据
        if(fulllen < emptyBuff.GetLength())
        {
            if(pCacheBuff != NULL)
            {
                pCacheBuff->Append(emptyBuff.SubArray(fulllen));
            }
            emptyBuff.RemoveTail(emptyBuff.GetLength() - fulllen);
        }
        return true;
    }
    /**
     * @brief 按照格式组数据
     * @date 2017-10-13 16:37
     * 
     * @param [in] data 需要发送的数据,长度在0x7E内
     * @param [out] buff 组好的发送报文
     */
    static void PackByFormat(const ByteArray& data, ByteBuilder& buff)
    {
        size_t lastLen = buff.GetLength();
        buff += ACK_STX;
        buff += _itobyte(data.GetLength());
        buff += data;

        byte lrc = ByteConvert::XorVal(buff.SubArray(lastLen));
        buff += lrc;
    }
    /// 解包数据
    static bool UnpackByFormat(const ByteArray& buff, ByteBuilder& data)
    {
        if(buff.GetLength() < 3)
            return false;
        size_t len = buff[1];
        size_t fulllen = (len + 3);
        if(buff.GetLength() < fulllen)
            return false;

        data += buff.SubArray(2, len);
        return true;
    }
protected:
    /// 临时缓冲区 
    ByteBuilder _tmpBuffer;
    /// 进行一次ACK指令交互
    bool _Write(const ByteArray& data)
    {
        LOGGER(_log<<"Send:"<<data<<endl);
        _tmpBuffer.Clear();
        PackByFormat(data, _tmpBuffer);

        ASSERT_FuncErr(_pDev->Write(_tmpBuffer), DeviceError::SendErr);
        _tmpBuffer.Clear();
        ASSERT_FuncErr(_pDev->Read(_tmpBuffer), DeviceError::RecvErr);
        LOGGER(_log<<"Recv:"<<_tmpBuffer<<endl);
        ASSERT_FuncErr(StringConvert::StartWith(_tmpBuffer, ACK_COMMAND), DeviceError::RecvFormatErr);
        _tmpBuffer.RemoveFront(ACK_COMMAND.GetLength());
        LOGGER(if(!_tmpBuffer.IsEmpty())
        {
            _log<<"Last:"<<_tmpBuffer<<endl;
        });
        return true;
    }
public:
    LC_ComStreamCmdAdapter() : DevAdapterBehavior() { IsCheckLRC = true; }
    /// 发送数据 
    virtual bool Write(const ByteArray& data)
    {
        LOG_FUNC_NAME();
        ASSERT_Device();
        size_t len = 0x7E;
        for(size_t i = 0;i < data.GetLength(); i += len)
        {
            if(!_Write(data.SubArray(i, len)))
            {
                return _logRetValue(false);
            }
        }
        return _logRetValue(true);
    }
    /// 接收数据 
    virtual bool Read(ByteBuilder& data)
    {
        LOG_FUNC_NAME();
        ASSERT_Device();
        if(!RecvByFormat(_pDev, _tmpBuffer))
        {
            // 接收失败时,清空已缓存的数据
            _tmpBuffer.Clear();
            _logErr(DeviceError::RecvErr);
            return _logRetValue(false);
        }
        LOGGER(_log << "RECV:" << _tmpBuffer << endl);

        size_t len = _tmpBuffer[1];
        ByteArray recvBuff = _tmpBuffer.SubArray(2, len);
        byte recvLrc = 0x00;
        byte lrc = recvLrc;
        if(IsCheckLRC)
        {
            // 比对LRC
            recvLrc = _tmpBuffer[_tmpBuffer.GetLength() - 1];
            _tmpBuffer.RemoveTail();

            lrc = ByteConvert::XorVal(_tmpBuffer);

            LOGGER(_log << "LRC:<" << _hex(lrc) << ">, RecvLRC:<" << _hex(recvLrc) << ">\n");
        }
        data += recvBuff;
        _tmpBuffer.Clear();
        ASSERT_FuncErrInfoRet(lrc == recvLrc, DeviceError::DevVerifyErr, "校验和错");
        // 回复应答包
        ASSERT_FuncErrRet(_pDev->Write(ACK_COMMAND), DeviceError::SendErr);
        return _logRetValue(true);
    }
    /**
     * @brief 是否校验LRC
     */
    bool IsCheckLRC;
    /// 清空接收ACK时提前返回的缓存数据,返回是否有缓存数据
    inline bool Clean()
    {
        bool isCached = !_tmpBuffer.IsEmpty();
        _tmpBuffer.Clear();
        return isCached;
    }
};
//--------------------------------------------------------- 
} // namespace lc
} // namespace application 
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_LC_COMSTREAMCMDADAPTER_H_
//========================================================= 

